package io.hellsinger.vortex.ui.component.adapter

import android.view.View
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import io.hellsinger.vortex.ui.component.adapter.diff.ItemDiffer
import io.hellsinger.vortex.ui.component.adapter.listener.ItemListener
import io.hellsinger.vortex.ui.component.item.button.ButtonItem
import io.hellsinger.vortex.ui.component.item.button.ButtonItemView
import io.hellsinger.vortex.ui.component.item.drawer.DrawerItemView
import io.hellsinger.vortex.ui.component.item.menu.MenuAction
import io.hellsinger.vortex.ui.component.item.title.TitleItemView
import io.hellsinger.vortex.ui.component.item.twoline.TwoLineItem
import io.hellsinger.vortex.ui.component.item.twoline.TwoLineItemView

open class ItemAdapter(
    private val listener: ItemListener,
    private val viewProvider: ItemViewProvider<View> = ItemViewProvider(Items::resolveViewType),
    private val viewBinder: ItemViewBinder<SuperItem, MultipleViewHolder> = ItemViewBinder { _, _ -> },
) : MultipleTypeAdapter() {
    constructor(
        listener: ItemListener,
        viewProvider: ItemViewProvider<View> = ItemViewProvider(Items::resolveViewType),
        viewBinder: ItemViewBinder<SuperItem, MultipleViewHolder> = ItemViewBinder { _, _ -> },
        initial: List<SuperItem>,
    ) : this(listener, viewProvider, viewBinder) {
        list.addAll(initial)
    }

    constructor(
        listener: ItemListener,
        viewProvider: ItemViewProvider<View> = ItemViewProvider(Items::resolveViewType),
        viewBinder: ItemViewBinder<SuperItem, MultipleViewHolder> = ItemViewBinder { _, _ -> },
        renderer: ListRenderer,
    ) : this(
        listener,
        viewProvider,
        viewBinder,
        renderer.render(),
    )

    constructor(
        listener: ItemListener,
        viewProvider: ItemViewProvider<View> = ItemViewProvider(Items::resolveViewType),
        viewBinder: ItemViewBinder<SuperItem, MultipleViewHolder> = ItemViewBinder { _, _ -> },
        block: MutableList<SuperItem>.() -> Unit,
    ) : this(listener, viewProvider, viewBinder) {
        list.apply(block)
    }

    private val clickListenerWrapper =
        OnClickListener { view ->
            listener.onItemClick(view, view.tag as Int)
        }

    private val longClickListenerWrapper =
        OnLongClickListener { view ->
            return@OnLongClickListener listener.onLongItemClick(view, view.tag as Int)
        }

    override fun createDiffer(new: List<Item<*>>): DiffUtil.Callback = ItemDiffer(list, new)

    override fun createView(
        parent: ViewGroup,
        viewType: Int,
    ) = viewProvider(parent, viewType)

    override fun onViewAttachedToWindow(holder: MultipleViewHolder) =
        Items.resolveViewTypeListener(
            holder.itemView,
            clickListenerWrapper,
            longClickListenerWrapper,
        )

    override fun onViewDetachedFromWindow(holder: MultipleViewHolder) =
        Items.resolveViewTypeListener(
            view = holder.itemView,
            clickListener = null,
            longClickListener = null,
        )

    override fun onBindViewHolder(
        holder: MultipleViewHolder,
        position: Int,
    ) {
        val item = list[position]
        when (item.viewType) {
            Items.DRAWER ->
                bind<DrawerItemView, MenuAction>(
                    holder,
                    item,
                )

            Items.TWO_LINE ->
                bind<TwoLineItemView, TwoLineItem>(
                    holder,
                    item,
                )

            Items.TITLE ->
                bind<TitleItemView, String>(
                    holder,
                    item,
                )

            Items.BUTTON ->
                bind<ButtonItemView, ButtonItem>(
                    holder,
                    item,
                )

            else -> viewBinder(holder, item)
        }
    }

    override fun onViewRecycled(holder: MultipleViewHolder) =
        when (holder.itemViewType) {
            Items.DRAWER ->
                unbind<DrawerItemView, MenuAction>(
                    holder,
                )

            Items.TWO_LINE ->
                unbind<TwoLineItemView, TwoLineItem>(
                    holder,
                )

            Items.TITLE ->
                unbind<TitleItemView, String>(
                    holder,
                )

            Items.BUTTON ->
                unbind<ButtonItemView, ButtonItem>(
                    holder,
                )

            else -> {}
        }
}
